package com.engine.knowledge;

import com.wolfram.alpha.WAEngine;
import com.wolfram.alpha.WAException;
import com.wolfram.alpha.WAPlainText;
import com.wolfram.alpha.WAPod;
import com.wolfram.alpha.WAQuery;
import com.wolfram.alpha.WAQueryResult;
import com.wolfram.alpha.WASubpod;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This is the main class of knowledge manipulation. Do not get confused between interpretation and knowledge
 * interpretation is done in other modules, here the real knowledge is handled. The first step would be to check
 * the internal repository (document database) to check if the searched knowledge can be found there, if not then
 * use whatever external knowledge base we have registered to find the information, store it in our local repository
 * and then return the answer.
 * @author Giank
 */
public class Master {
    
    public String provider;
    private String APIKey;
    private WAEngine engine;
    private WAQuery query;
    private final static Logger LOG = Logger.getLogger(Master.class .getName()); 
    
    /**
     * Class constructor and variable initializer
     */
    public Master(){
        loadProperties();
        
        // The WAEngine is a factory for creating WAQuery objects,
        // and it also used to perform those queries. You can set properties of
        // the WAEngine (such as the desired API output format types) that will
        // be inherited by all WAQuery objects created from it. Most applications
        // will only need to crete one WAEngine object, which is used throughout
        // the life of the application.
        engine = new WAEngine();
        
        // These properties will be set in all the WAQuery objects created from this WAEngine.
        engine.setAppID(this.APIKey);
        engine.addFormat("plaintext");

        // Create the query.
        query = engine.createQuery();
    }

    /**
     * Load main properties for knowledge acquisition
     */
    private void loadProperties(){
        // Read properties file.
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src/main/resources/configuration.properties"));
            this.provider = properties.getProperty("externalKnowledgeBase");
            this.APIKey  = properties.getProperty("externalKnowledgeBaseAPIKey");
        } catch (IOException e) {
            LOG.log(Level.SEVERE, "Error reading the configuration.properties file");
        }
    }
    
    public String answer(String message){
        String result = "";
        WAQueryResult queryResult = null;
        try {
            query.setInput(message);
            queryResult = engine.performQuery(query);

            if (queryResult.isError()) {
                LOG.log(Level.SEVERE,   "WAExpection - Master.answer query error " + " .code: {0} .message: {1}", new Object[]{queryResult.getErrorCode(), queryResult.getErrorMessage()});
            } else if (!queryResult.isSuccess()) {
                LOG.log(Level.INFO, "WAWarning - Master.answer Query was not understood; no results available. Given .message:{0}", message);
            } else {
                // Got a result.
                for (WAPod pod : queryResult.getPods()) {
                    if (!pod.isError()) {
                        //result+=pod.getTitle()+"\n";
                        for (WASubpod subpod : pod.getSubpods()) {
                            for (Object element : subpod.getContents()) {
                                if (element instanceof WAPlainText) {
                                    result+=((WAPlainText) element).getText()+"\n";
                                }
                            }
                        }
                    }
                }
                // We ignored many other types of Wolfram|Alpha output, such as warnings, assumptions, etc.
                // These can be obtained by methods of WAQueryResult or objects deeper in the hierarchy.
            }
        } catch (WAException ex) {
            LOG.log(Level.SEVERE, "WAExpection - Master.answer for .input: "+message, ex);
        } catch (Exception ex) {
            LOG.log(Level.SEVERE, "Unexpected exception - Master.answer for .input: "+message, ex);
        } finally {
            if (queryResult!=null){
                queryResult.release();
            }
        }
        
        return result;
    }
    
}
